使用Spring AOP过程中,可能遇到过下列奇怪问题:
- 类内部方法间调用AOP不起作用
- 类内部方法间调用事务不起作用
- 内部类异步线程调用外层方法事务不起作用
由于Spring的事务底层也是用AOP实现的,因此,这些症状都可以归结为,类内部方法间调用AOP失效。
举个官网例子:
The key thing to understand here is that the client code inside the
main(..)method of theMainclass has a reference to the proxy. This means that method calls on that object reference are calls on the proxy. As a result, the proxy can delegate to all of the interceptors (advice) that are relevant to that particular method call. However, once the call has finally reached the target object (theSimplePojo, reference in this case), any method calls that it may make on itself, such asthis.bar()orthis.foo(), are going to be invoked against thethisreference, and not the proxy. This has important implications. It means that self-invocation is not going to result in the advice associated with a method invocation getting a chance to execute.
在main方法中,我们为SimplePojo创建了一个代理对象,pojo是代理对象的引用。
当调用foo()方法时,其实是调用代理对象的方法,我们可以在代理对象中添加拦截器对方法进行增强。
注意,foo()方法内部调用this.bar()时,是在this引用上的,并非代理对象引用,因此,不会被拦截到,无法增强。
那怎么解决这个问题呢?
The best approach is to refactor your code such that the self-invocation does not happen.
官网推荐做法:干掉内部调用。。。
如果干不掉呢?
那就得跟Spring AOP强绑定起来:
或者在一个bean里面,从Spring容器中手动获取bean进行调用:
还有一种方法是在bean中引入自己:
但是这种方式容易产生循环依赖,没有使用。
还有一种方法,是使用AspectJ的AOP代替Spring AOP的代理方式。在编译器进行代码织入。但是自己用的比较少,这里不做介绍了。